

<template>
    <div class="d3-container">
        <div class="btns" style=" position: absolute; top:20px;left:340px;height:0px;width:500px">
            <el-button-group  style="font-size: 150px">
                <el-button type="info" id="zoomIn" size="medium" round>
                    <el-icon><zoom-in /></el-icon>
                    <span style="vertical-align: middle; font-size: 12px">zoom-in </span>
                </el-button>
                <el-button type="info"  id="zoomOut" size="medium" round>
                    <el-icon ><zoom-out /></el-icon>
                    <span style="vertical-align: middle;font-size: 12px">zoom-out </span>
                </el-button>
                <el-button type="info" id="reset" size="medium" round>
                    <el-icon><refresh-right /></el-icon>
                    <span style="vertical-align: middle;font-size: 12px">reset </span>
                </el-button>
                <el-button type="info" id="download" size="medium" round>
                    <el-icon><download /></el-icon>
                    <span style="vertical-align: middle;font-size: 12px">download </span>
                </el-button>

            </el-button-group>
        </div>
        <svg class="svg" width="1400" height="800" style="position: absolute; top:0px; left: -15px; " viewBox="0 0 0 0"/>
        <div id="imginfo" style="position: absolute; top:20px; right: 10px; width: 250px;height: 250px ;" >
            <el-dialog
                    title="详细资料"
                    v-model="dialogVisible"
                    class="el-dialog"
                    width="28%"
            >
                <span id="span-text">{{info}}</span>
                <template #footer>
                <span class="dialog-footer">
                  <el-button @click="dialogVisible = false">取 消</el-button>
                  <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
                    </span>
                </template>
            </el-dialog>
        </div>
    </div>
</template>

<script>
    import * as d3 from 'd3'
    import imgs from './imgjson.json'
    import starinfo from './starspecificinfo.json'
    import bus from '../utils/bus'

    export default {
        name: "testGraph2",
        components: {},
        data() {
            return {
                info: '123',
                nodes: [], // 节点集
                // nodes2:[],
                links2: [],
                links: [], // 关系集
                source: 265,
                target: 462,
                visibleFlag: false,
                dialogVisible: false,
            }
        },
        watch: {
            nodes() {
                this.$nextTick(() => {
                    console.log("change links")
                    console.log(this.links2)
                    d3.select('.svg').selectAll('*').remove()
                    this.initD3()
                    // this.initD3()
                })
            }
        },

        // created:vue生命周期中的钩子函数，在这个时间点，data中的数据已经注入到响应式系统中
        /* created和mounted执行时，异步初始化还没执行（还没执行完），
    也就是created里的数据还没获取到，mounted就开始了渲染视图的工作，
    那么这时模型层数据肯定就是为空的啦，而mounted只会调用一次，这就陷入了一个死局，
    mounted永远等不到created获取完数据后在渲染，
    那么解决的方法就是为mounted中的方法设置一个定时器，
    因为created获取数据的速度是很快的，我们只用让mounted停那么一丢丢时间就ok了！*/
        mounted() {
            bus.on('sendBybus', e => {
                // console.log("bus data:")
                console.log(e)
                console.log(e.nodes)
                var jsonstr = eval(e.nodes)
                const len = jsonstr.length
                const tempJson = {}
                const res = []
                for (let i = 0; i < len; i++)
                    tempJson[JSON.stringify(jsonstr[i])] = true;
                const keyItems = Object.keys(tempJson)
                for (let j = 0; j < keyItems.length; j++) {
                    res.push(JSON.parse(keyItems[j]))
                }

                var jsonstr2 = eval(e.message)
                const len2 = jsonstr2.length
                const tempJson2 = {}
                const res2 = []
                for (let i = 0; i < len2; i++)
                    tempJson2[JSON.stringify(jsonstr2[i])] = true;
                const keyItems2 = Object.keys(tempJson2)
                for (let j = 0; j < keyItems2.length; j++) {
                    res2.push(JSON.parse(keyItems2[j]))
                }
                // var jsonObject=JSON.parse(jsonstr[0])
                var st = eval(e.sourceTarget)
                this.source = st[0]['source']
                this.target = st[0]['target']
                this.nodes = res
                this.links2 = res2
                console.log(this.source)
                console.log(this.target)
                // this.nodes2=JSON.parse(JSON.stringify(res))
            })


        },
        created() {
            this.jsonpData()
        },

        methods: {
            handleClose(done) {
                this.$confirm('确认关闭？')
                    .then(_ => {
                        done();
                    })
                    .catch(_ => {
                    });
            },
            //svg 保存成Png  fuction
            svgToPng: function (svg, pngWidth, pngHeight) {
                //保存前将image元素删除 以及节点文字居中
                console.log(svg.node())
                d3.selectAll('.node-image').remove()
                d3.selectAll('.node-text')
                    .attr("dy", ".35em")
                var serializer = new XMLSerializer();
                var source = '<?xml version="1.0" standalone="no"?>\r\n' + serializer.serializeToString(svg.node());
                var image = new Image;
                var url = "";
                image.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
                var canvas = document.createElement("canvas");
                canvas.width = pngWidth;
                canvas.height = pngHeight;
                var context = canvas.getContext("2d");
                context.fillStyle = '#000';//设置保存后的PNG 是白色的
                context.fillRect(0, 0, 10000, 10000);
                image.onload = function () {
                    context.drawImage(image, 0, 0);
                    var a = document.createElement("a");
                    a.download = "relation.png";
                    a.href = canvas.toDataURL("image/png");
                    a.click();
                }

                //保存后返回原样
                d3.selectAll('.node-text')
                    .attr("dy", "40px")
                const starimg = eval(imgs)
                d3.selectAll('.node-pattern')
                    .append("svg:image")
                    .attr('class', 'node-image')
                    .attr("width", 50)
                    .attr("height", 50)
                    // .attr("xlink:href","https://img2.baidu.com/it/u=494908555,808736966&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500")
                    .attr("xlink:href", function (d) {
                        const url = starimg[d.id]['imgurl']
                        return url
                    })


            },
            jsonpData: function () {
                const that = this
                var url = '/api/graph/getNodes/' // 这里就是刚才的config/index.js中的/api
                this.axios.get(url)
                    .then(response => {
                        console.log(response.data.nodes)
                        console.log(response.data.message)
                        var jsonstr = eval(response.data.nodes)
                        const len = jsonstr.length
                        const tempJson = {}
                        const res = []
                        for (let i = 0; i < len; i++)
                            tempJson[JSON.stringify(jsonstr[i])] = true;
                        const keyItems = Object.keys(tempJson)
                        for (let j = 0; j < keyItems.length; j++) {
                            res.push(JSON.parse(keyItems[j]))
                        }
                        // var jsonObject=JSON.parse(jsonstr[0])
                        // console.log(res)

                        var jsonstr2 = eval(response.data.message)
                        const len2 = jsonstr2.length
                        const tempJson2 = {}
                        const res2 = []
                        for (let i = 0; i < len2; i++)
                            tempJson2[JSON.stringify(jsonstr2[i])] = true;
                        const keyItems2 = Object.keys(tempJson2)
                        for (let j = 0; j < keyItems2.length; j++) {
                            res2.push(JSON.parse(keyItems2[j]))
                        }
                        // var jsonObject=JSON.parse(jsonstr[0])
                        // console.log(res2)
                        /* self.$nextTick(()=>{
                                self.nodes=res
                                self.links=res2
                            })*/
                        that.nodes = res
                        that.links2 = res2
                        that.nodes2 = JSON.parse(JSON.stringify(res))
                        console.log("nodes:jsondata")
                        console.log(that.nodes)
                    })
                    .catch(error => {
                        console.log(error);
                    });
            },
            initD3() {
                const _this = this
                console.log("nodes:initD3")
                console.log(_this.links2)
                // 容器
                const svg = d3.select('.svg')
                    .attr('viewBox', [-window.innerWidth / 2, -window.innerHeight / 2, 1400, 800])
                // 缩放
                const svgcontainer=svg.append('g')

                const zoom = d3.zoom()
                    .scaleExtent([0.1, 10])
                        .on('start', () => { // zoom 事件发生前 将变小手
                        svg.style('cursor', 'pointer')
                    })
                    .on('zoom', function () {
                        svgcontainer.transition().duration(250).attr('transform', d3.event.transform)

                    })
                      // d3.selectAll('g').call(zoom)
                svgcontainer.call(zoom)
                     // svg.call(zoom)
                d3.select('#reset')
                    .on('click', function () {
                        svgcontainer.call(zoom.transform, d3.zoomIdentity)
                    })
                d3.select('#zoomIn')
                    .on('click', function () {
                        zoom.scaleBy(svgcontainer, 1.1)
                    })
                d3.select('#zoomOut')
                    .on('click', function () {
                        zoom.scaleBy(svgcontainer, 0.9) // 执行该方法后 会触发 zoom 事件 0.9 缩小
                    })
                d3.select('#download').on('click', function () {
                    _this.svgToPng(svg, window.innerWidth, window.innerHeight)
                })
                d3.select('#textButton').on('click', function () {
                    _this.dialogVisible = true
                })
                // 新建一个力导向图
                const simulation = d3.forceSimulation()
                    .force('charge', d3.forceManyBody().strength(-600))//节点间电荷数
                    .force('link', d3.forceLink().id(d => d.id).distance(250))
                    .force("center", d3.forceCenter(-150,-70))
                    .force('collide',d3.forceCollide().radius(35))
                    .force('x', d3.forceX())
                    .force('y', d3.forceY())
                    .force('yt', d3.forceY().strength(() => 0.025))
                    .force('yb', d3.forceY(window.innerHeight).strength(() => 0.025))
                    // // 在 y轴 方向上施加一个力把整个图形压扁一点
                    .on('tick',ticked)



                // 关系路径
                let link = svgcontainer.append('g')
                    .attr('class', 'link-container')
                    .attr('stroke', '#FFFFFF')
                    .attr('stroke-width', 3)
                    .selectAll('line')
                    .call(zoom)


                // 关系文字
                let linkText = svgcontainer.append('g')
                    .attr('class', 'link-text-container')
                    .attr('stroke', '#FFFFFF')
                    .attr('stroke-width', 1.5)
                    .selectAll('text')
                    .call(zoom)

                // 节点
                let node = svgcontainer.append('g')
                    .attr('class', 'node-container')
                    .selectAll('circle')
                    .call(zoom)
                function ticked() {

                    node

                        .attr('transform', function (d) {
                            return 'translate(' + d.x + ',' + d.y + ')'
                        })


                    link.attr('x1', d => d.source.x)
                        .attr('y1', d => d.source.y)
                        .attr('x2', d => d.target.x)
                        .attr('y2', d => d.target.y)

                    linkText
                        .attr('x', d => (d.source.x + d.target.x) / 2)
                         .attr('y', d => (d.source.y + d.target.y) / 2 + (d.source.id > d.target.id ? 12 : -12))
                        .attr("transform",function (d) {

                                if(d.target.x==d.source.x)
                                {
                                    const  angle=90
                                    return 'rotate('+angle+","+(d.source.x + d.target.x)/ 2+","+(d.source.y + d.target.y)/ 2+")"
                                }
                                const k=(d.target.y-d.source.y)/(d.target.x-d.source.x)
                                const angle=Math.atan(k)*180/Math.PI;
                                return 'rotate('+angle+","+(d.source.x + d.target.x)/ 2+","+(d.source.y + d.target.y)/ 2+")"
                        })
                }

                // 更新
                const updateObj = Object.assign(svgcontainer.node(), {
                    update({nodes, links}) {
                        console.log("update links")
                        console.log(links)
                        console.log("update nodes")
                        console.log(nodes)
                        // 做一个浅复制，以防止突变，回收旧节点以保持位置和速度
                        // const old = new Map(node.data().map(d => [d.id, d]))
                        nodes = nodes.map(d => Object.assign({}, d))
                        links = links.map(d => Object.assign({}, d))
                        // 节点
                        node = node
                            .data(nodes, d => d.id)
                            .join(enter => enter.append('g')
                                .attr('class', 'single-node')
                                .attr('id', (d) => {
                                    return 'single-node' + d.id
                                })
                            )
                            .call(d3.drag()
                                .on('start', dragstarted)
                                .on('drag', dragged)
                                .on('end', dragended))

                        //给每个节点填充颜色
                        d3.selectAll('.single-node')
                            .append('circle')
                            .attr('r', 25)
                            .attr('fill', nodeColor)
                            //一种css样式，鼠标移动到上面会从箭头变成手的样子
                            .style('cursor', 'pointer')
                        const starimg = eval(imgs)


                        //给节点添加圆形图片
                       var def= d3.selectAll('.single-node')
                            .append("svg:defs")

                        def.append("svg:pattern")
                            .attr('class', 'node-pattern')
                            .attr("id", function (d) {
                                return d.id
                            })
                            .attr("patternUnits", "userSpaceOnUse")
                            .attr("x", -25)
                            .attr("y", -25)
                            .attr("width", 100)
                            .attr("height", 100)
                            .append("svg:image")
                            .attr('class', 'node-image')
                            .attr("width", 50)
                            .attr("height", 50)
                            // .attr("xlink:href","https://img2.baidu.com/it/u=494908555,808736966&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500")
                            .attr("xlink:href", function (d) {
                                const url = starimg[d.id]['imgurl']
                                return url
                            })



                        d3.selectAll('.single-node')
                            .append('circle')
                            .attr("r", 20)
                            .attr("fill", function (d) {
                                return "url(#" + d.id + ")"
                            })




                        //给起点和终点标记
                        d3.selectAll('.single-node').each(function (d) {
                            const temp = d.id
                            // console.log(_this.source)
                            if (temp === _this.source || temp == _this.target) {
                                d3.select(this).select('circle')
                                        .attr("stroke","red")
                                        .attr("stroke-width","4")
                                       .attr("stroke-dasharray", "4,2");
                               }

                            })

                        // 节点文字
                        d3.selectAll('.single-node')
                            .append('text')
                            .attr('class', 'node-text')
                            .attr("dy", "40px")
                            .attr("text-anchor", "middle")//在圆圈中加上数据
                            .attr('stroke', '#FFFFFF')
                            .style('cursor', 'pointer')
                            // .attr('x', function (d) {
                            //     return textBreaking(d3.select(this), d, false)
                            // })
                            .text(function (d) {
                                return d.name
                            })
                            .attr('font-size', 15)

                        // 绘制箭头
                        svgcontainer.append('g')
                            .attr('class', 'arrow-marker')
                            .append('marker')
                            .attr('id', 'arrow-marker')
                            .attr('markerUnits', 'strokeWidth') // 设置为 strokeWidth 箭头会随着线的粗细发生变化
                            .attr('markerUnits', 'userSpaceOnUse')
                            .attr('viewBox', '0 -5 10 10') // 坐标系的区域
                            .attr('refX', 34) // 箭头坐标
                            .attr('refY', 0)
                            .attr('markerWidth', 10) // 标识的大小 箭头的宽度和高度
                            .attr('markerHeight', 10)
                            .attr('orient', 'auto') // 绘制方向，可设定为：auto（自动确认方向）和 角度值
                            .attr('stroke-width', 3) // 箭头宽度
                            .append('path')
                            .attr('d', 'M0,-5 L10,0 L0,5') // 箭头的路径
                            .attr('fill', '#FFFFFF') // 箭头颜色
                            .call(zoom)

                        // 关系路径
                        link = link
                            .data(links, d => [d.source, d.target])
                            //数据绑定
                            .join(
                                enter => enter.append('line')
                                    .attr('class', 'single-line')
                                    .attr('id', function (d) {
                                        return 'single-line' + d.id
                                    })
                                    .attr('marker-end', 'url(#arrow-marker)') // 根据箭头标记的 id 号标记箭头
                            )

                        // 路径文字
                        linkText = linkText
                            .data(links, d => [d.source, d.target])
                            .join(
                                enter => enter.append('text')
                                    .attr('class', 'link-text')
                                    .attr('id', (d) => {
                                        return 'link-text' + d.id
                                    })
                                    .text((d) => {
                                        return d.relation
                                    })
                                    .attr("dy", ".35em")
                                    .attr("text-anchor", "middle")//在圆圈中加上数据
                                    .attr('stroke', function (d) {
                                        const node = d.source
                                        var result = ""
                                        d3.selectAll('.single-node').each(function (d) {
                                            const temp = d.id
                                            if (temp === node) {
                                                result = "" + d3.select(this).select('circle').attr('fill')
                                            }
                                        })
                                        return result
                                    })
                                    .attr('stroke-width', '1')
                                    .attr('fill', 'none')
                                    .style('cursor', 'pointer')

                            )

                        simulation.nodes(nodes)
                        simulation.force('link').links(links)
                        simulation.alpha(1).restart()

                        node.on('click', function (d) {
                            _this.visibleFlag = !_this.visibleFlag
                            toggleMenu(d3.select(this), d, _this.visibleFlag)

                        })
                            .on('mouseover', function (d) {
                                // 鼠标移入节点，高亮当前节点及与当前节点有关系的路径和节点
                                d3.selectAll('.single-node').style('opacity', 0.2)
                                d3.selectAll('.single-line').style('opacity', 0.2)
                                d3.selectAll('.link-text').style('opacity', 0.2)
                                d3.select('#single-node' + d.id).style('opacity', 1)
                                const relationLinks = []
                                /* _this.links.forEach((item)=>{
                                        console.log(item.source)
                                    })*/
                                _this.links.forEach((item) => {
                                    if (item.source === d.id || item.target === d.id) {
                                        relationLinks.push(item)
                                    }
                                })
                                relationLinks.forEach((item) => {
                                    d3.select('#single-line' + item.id).style('opacity', 1)
                                    d3.select('#link-text' + item.id).style('opacity', 1)
                                    d3.select('#single-node' + item.source).style('opacity', 1)
                                    d3.select('#single-node' + item.target).style('opacity', 1)
                                })
                                // _this.info = JSON.stringify(d)
                                console.log("img"+d.id)
                                d3.select("#imginfo")
                                    .append('div')
                                    .attr('class', "node-img")
                                    .attr('id', 'img' + d.id)
                                    .append('img')
                                     .attr("width", "250px")
                                    .attr("src", starimg[d.id]['imgurl'])

                            })
                            .on('mouseout', function (d) {
                                d3.selectAll('.single-node').style('opacity', 1)
                                d3.selectAll('.single-line').style('opacity', 1)
                                d3.selectAll('.link-text').style('opacity', 1)
                                 d3.select('#img' + d.id).remove()

                            })
                    }

                })
                const relation = _this.links2
                const edge = []
                for (let i = 0; i < relation.length; i++) {
                    edge[i] = {
                        id: '' + relation[i].source + '' + '' + relation[i].target + '',
                        source: relation[i].source,
                        target: relation[i].target,
                        relation: relation[i].type
                    }
                }
                _this.links.splice(0, _this.links.length)
                edge.forEach((item) => {
                    _this.links.push(item)
                })

                updateObj.update({
                    nodes: _this.nodes,
                    links: _this.links
                })

                /**
                 * @name: 设置节点颜色
                 * @param {*} node
                 */
                function nodeColor(node) {
                    const colors = ['#F4AB87', '#EEC88D', '#76CADF', '#97DA9D', '#88DCD8', '#FB7F89', '#F0E403', '#F576BE', '#ACADFF', '#7EC3FB', '#D0DB02', '#C07B11', '#00ACC2', '#2AAD41', '#A59D00', '#CD0EBD', '#DE3997']
                    return colors[Math.floor(node.id % colors.length)]
                }

                /**
                 * @name: 标记
                 * @param {*} node
                 */
                function setRedColor(node) {
                    const clickNode = node.id
                    d3.selectAll('.single-node').each(function (d) {
                        const temp = d.id
                        // 删除当前需要隐藏的节点
                        let it=d3.select(this).select('circle')
                        if (temp === clickNode) {
                            if(it.attr('stroke')===null){
                                d3.select(this).select('circle')
                                    .attr("stroke","red")
                                    .attr("stroke-width","4")
                                    .attr("stroke-dasharray", "4,2")
                            }
                            else{
                                d3.select(this).select('circle')
                                    .attr('stroke',null)
                                    .attr("stroke-width",null)
                                    .attr("stroke-dasharray", null)
                            }
                        }
                    })
                }

                /**
                 * @name: 关联节点去重重组
                 * @param {*} objarray
                 */
                function uniqObjInArray(objarray) {
                    const len = objarray.length
                    const tempJson = {}
                    const res = []
                    for (let i = 0; i < len; i++) {
                        // 取出每一个对象
                        tempJson[JSON.stringify(objarray[i])] = true
                    }
                    const keyItems = Object.keys(tempJson)
                    for (let j = 0; j < keyItems.length; j++) {
                        res.push(JSON.parse(keyItems[j]))
                    }
                    return res
                }



                /**
                 * @name: 隐藏，删除当前及下一级没有其他关系的节点
                 * @param {*} node
                 */
                function deleteNodeAndLinks(node) {
                    const removeIndex = _this.nodes.findIndex(data => data.id === node.id)
                    _this.nodes.splice(removeIndex, 1)//从node节点中删除索引为removeIndex 的一个
                    const relationNode = []
                    const relationList = []
                    const clickNode = node.id
                    d3.selectAll('.single-line').each(function (e) {
                        if (e.source.id === node.id || e.target.id === node.id) {
                            d3.select(this).remove()
                        } else {
                            relationList.push(e)
                        }
                        // 需要删除的节点相关的节点
                        if (e.source.id === node.id) {
                            relationNode.push(e.target)
                        }
                    })
                    //JSON.stringfy 序列化为字符串 JSON.parse反序列化为js对象  深拷贝
                    let tempNodeList = JSON.parse(JSON.stringify(relationNode))
                    tempNodeList = uniqObjInArray(tempNodeList)
                    // 区分下级节点是否是孤节点
                    tempNodeList.forEach(function (item) {
                        const hasLine = relationList.findIndex(jtem => jtem.target.id === item.id || jtem.source.id === item.id)
                        if (hasLine >= 0) {
                            item.notSingle = true
                        }
                    })
                    tempNodeList.forEach(function (item) {
                        if (!item.notSingle) {
                            d3.select('#single-node' + item.id).remove()
                        }
                    })
                    d3.selectAll('.single-node').each(function (d) {
                        const temp = d.id
                        // 删除当前需要隐藏的节点
                        if (temp === clickNode) {
                            d3.select('.menu-circle').remove()
                            d3.select(this).remove()
                        }
                    })
                    d3.selectAll('.link-text').each(function (e) {
                        if (e.source === node || e.target === node) {
                            d3.select(this).remove()
                        }
                    })
                }

                /**
                 * @name: 生成操作菜单
                 * @param {*} current 当前元素
                 * @param {*} d 当前元素对应的数据
                 * @param {*} flag 显隐
                 */
                function toggleMenu(current, d, flag) {
                    const currentD = d
                    const data = [{
                        population: 33,
                        value: '隐藏',
                        type: 'delete'
                    }, {
                        population: 33,
                        value: '详情',
                        type: 'showOn'
                    }, {
                        population: 33,
                        value: '标记',
                        type: 'showOff'
                    }]
                    // 创建一个环生成器
                    const arc = d3.arc()
                        .innerRadius(70) // 内半径
                        .outerRadius(30) // 外半径
                    const pie = d3.pie()
                        .value(function (d) {
                            return d.population
                        })
                        .sort(null)
                    const pieData = pie(data)
                    const pieAngle = pieData.map(function (p) {
                        return (p.startAngle + p.endAngle) / 2 / Math.PI * 180
                    })
                    // 菜单容器
                    const g = current
                        .append('g')
                        .attr('class', 'menu-circle')
                        .attr('width', 100)
                        .attr('height', 100)
                    const Pie = g.append('g')
                    Pie.selectAll('path')
                        .data(pie(data))
                        .enter()
                        .append('path')
                        .attr('d', arc)
                        .attr('fill', '#d3d7dc')
                        .style('stroke', '#fff')
                        .style('cursor', 'pointer')
                        .on('click', function (d) {
                            if (d.data.type === 'delete') {
                                d3.select('#img' + currentD.id).remove()
                                deleteNodeAndLinks(currentD)
                                d3.selectAll('.single-node').style('opacity', 1)
                                d3.selectAll('.single-line').style('opacity', 1)
                                d3.selectAll('.link-text').style('opacity', 1)

                            } else if (d.data.type === 'showOn') {
                                d3.select('#img' + currentD.id).remove()
                                _this.info=starinfo[currentD.id]['starinfo']
                                _this.dialogVisible = true
                            } else {
                                setRedColor(currentD)
                            }
                            d3.event.stopPropagation()
                        })
                        .on('mouseover', function () {
                            d3.select(this)
                                .style('fill', '#d3d7dc')
                                .transition()
                                .style('fill', '#aaaeb4')
                        })
                        .on('mouseout', function () {
                            d3.select(this)
                                .style('fill', '#aaaeb4')
                                .transition()
                                .style('fill', '#d3d7dc')
                        })

                    // 圆环上的文字
                    const labelFontSize = 13
                    const labelValRadius = (170 * 0.35 - labelFontSize * 0.35)
                    const labelValRadius1 = (170 * 0.35 + labelFontSize * 0.35)
                    const labelsVals = current
                        .select('.menu-circle')
                        .append('g')
                        .classed('labelsvals', true)
                    // 定义两条路径以使标签的方向正确
                    labelsVals.append('def')
                        .append('path')
                        .attr('id', 'label-path-1')
                        .attr('d', `m0 ${-labelValRadius} a${labelValRadius} ${labelValRadius} 0 1,1 -0.01 0`)
                    labelsVals.append('def')
                        .append('path')
                        .attr('id', 'label-path-2')
                        .attr('d', `m0 ${-labelValRadius1} a${labelValRadius1} ${labelValRadius1} 0 1,0 0.01 0`)
                    labelsVals.selectAll('text')
                        .data(data)
                        .enter()
                        .append('text')
                        .attr('dy', function (d) {
                            if (d.type === 'showOn') {
                                return -5
                            } else {
                                return 5
                            }
                        })
                        .style('font-size', labelFontSize)
                        .style('fill', 'black')
                        .style('font-weight', 'bold')
                        .style('text-anchor', 'middle')
                        .append('textPath')
                        .style('cursor', 'pointer')
                        .attr('href', function (d, i) {
                            const angle = pieAngle[i]
                            if (angle > 90 && angle <= 270) { // 根据角度选择路径
                                return '#label-path-2'
                            } else {
                                return '#label-path-1'
                            }
                        })
                        .attr('startOffset', function (d, i) {
                            const p = pieData[i]
                            const angle = pieAngle[i]
                            const percent = (p.startAngle + p.endAngle) / 2 / 2 / Math.PI * 100
                            if (angle > 90 && angle <= 270) { // 分别计算每条路径的正确百分比
                                return 100 - percent + '%'
                            }
                            return percent + '%'
                        })
                        .text(function (d) {
                            return d.value
                        })
                        .on('click', function (d) {
                            if (d.type === 'delete') {
                                d3.select('#img' + currentD.id).remove()
                                deleteNodeAndLinks(currentD)
                                d3.selectAll('.single-node').style('opacity', 1)
                                d3.selectAll('.single-line').style('opacity', 1)
                                d3.selectAll('.link-text').style('opacity', 1)
                            } else if (d.type === 'showOn') {
                                d3.select('#img' + currentD.id).remove()
                                _this.info=starinfo[currentD.id]['starinfo']
                                _this.dialogVisible = true
                            } else {
                                setRedColor(currentD)
                            }
                            d3.event.stopPropagation()
                        }, true)
                    if (flag === false) {
                        d3.selectAll('.menu-circle').remove()
                    }
                }

                /**
                 * @name: 节点文字换行
                 * @param {*} dom
                 * @param {*} data
                 * @param {*} breaking 是否换行
                 */
                function textBreaking(dom, data, breaking) {
                    const text = data.name
                    if (breaking) {
                        const len = text.length
                        if (len <= 3) {
                            dom.append('tspan')
                                .attr('x', 0)
                                .attr('y', 0)
                                .text(text)
                        } else {
                            const topText = text.substring(0, 3)
                            const midText = text.substring(3, 7)
                            let botText = text.substring(7, len)
                            let topY = -22
                            let midY = 8
                            const botY = 34
                            if (len <= 9) {
                                topY += 10
                                midY += 10
                            } else {
                                botText = text.substring(7, 9) + '...'
                            }
                            dom.text('')
                            dom.append('tspan')
                                .attr('x', 0)
                                .attr('y', topY)
                                .text(function () {
                                    return topText
                                })
                            dom.append('tspan')
                                .attr('x', 0)
                                .attr('y', midY)
                                .text(function () {
                                    return midText
                                })
                            dom.append('tspan')
                                .attr('x', 0)
                                .attr('y', botY - 7)
                                .text(function () {
                                    return botText
                                })
                        }
                    } else {
                        dom.append('tspan')
                            .attr('x', 0)
                            .attr('y', 0)
                            .style('font-size', 12)
                            .style('stroke', '#333')
                            .text(data.name)
                    }
                }

                /**
                 * @name: 拖动
                 * @param {*} event
                 */
                function dragstarted(event) {
                    if (!d3.event.active) {
                        simulation.alphaTarget(0.8).restart() // 设置衰减系数，对节点位置移动过程的模拟，数值越高移动越快，数值范围[0, 1]
                    }
                    event.fx = event.x
                    event.fy = event.y
                }

                function dragged(event) {
                    event.fx = d3.event.x
                    event.fy = d3.event.y
                }

                function dragended(event) {
                    if (!d3.event.active) {
                        simulation.alphaTarget(0)
                    }
                    event.fx = null
                    event.fy = null
                }


                /*   // 模拟接口返回节点信息
                    _this.$nextTick(() => {
                        // 初次返回节点
                      /!*  const res = {
                            'code': 0,
                            'message': '',
                            'data': {
                                'id': '0',
                                'name': '蔡成功',
                                }
                            }*!/
                        let data =[]
                         // data=_this.nodes

                        console.log("links:")
                        console.log(_this.links2)
                        const  relation=_this.links2
                        // _this.links.push(relation)
                        const edge=[]
                        for (let i = 0; i < relation.length; i++) {
                            edge[i] = {
                                id:''+relation[i].source+''+''+relation[i].target+'',
                                source: relation[i].source,
                                target: relation[i].target,
                                relation: relation[i].type
                            }
                        }
                        edge.forEach((item) => {
                            _this.links.push(item)
                        })

                        updateObj.update({
                            nodes: _this.nodes,
                            links: _this.links
                        })
                    })*/
            }
        }
    }
</script>

<style >
    .el-dialog{
        margin: 5% 6% auto auto !important;
        max-height: calc(100% - 50px);
        max-width: calc(100% - 50px);
        display: flex;
        flex-direction: column;
    }
    .el-dialog .el-dialog__body {
        padding: 3px 30px;
        overflow-y: auto;
        height: calc(50vh - 20px);
    }

    .d3-container {
        position: relative;
    }

    .d3-container .info {
        background: #fff;
        position: absolute;
        left: 50px;
        bottom: 50px;
        z-index: 9;
    }

    .d3-container .btns {
        background: #fff;
        position: absolute;
        right: 50px;
        bottom: 200px;
        z-index: 99;
    }

    .d3-container .btns span {
        cursor: pointer;
    }

    .d3-container .types {
        position: absolute;
        left: 50px;
        top: 50px;
        z-index: 9;
    }

    .d3-container .types span {
        display: inline-block;
        background: #a5abb6;
        border-radius: 4px;
        margin-right: 10px;
        padding: 5px 6px;
        cursor: pointer;
        color: #2e0f00;
        font-size: 12px;
    }
    .dialog-footer button:first-child {
        margin-right: 10px;
    }



</style>
